<html>
 <head>
  <meta charset="UTF-8">
 </head>
 <body>
  <h1 data-lake-id="kEKRC" id="kEKRC"><span data-lake-id="u2d330a81" id="u2d330a81">典型回答</span></h1>
  <p data-lake-id="ucab132db" id="ucab132db"><span data-lake-id="u448ece92" id="u448ece92">慢查询是指数据库中查询时间超过指定阈值的SQL，这个阈值根据不同的业务来说一般是不一样的，在我们内部，这个阈值是1s，也就是说，如果一条SQL执行超过1秒钟，就认为是一个慢SQL。</span></p>
  <p data-lake-id="u1e48024e" id="u1e48024e"><br></p>
  <p data-lake-id="u66acb87f" id="u66acb87f"><span data-lake-id="u123dffc8" id="u123dffc8">慢SQL的问题排查一般分为几个步骤。</span></p>
  <p data-lake-id="u167a960f" id="u167a960f"><span data-lake-id="u336d1aab" id="u336d1aab">​</span><br></p>
  <h3 data-lake-id="Gft9i" id="Gft9i"><span data-lake-id="ua209d2f4" id="ua209d2f4">发现问题</span></h3>
  <p data-lake-id="u76e26519" id="u76e26519"><span data-lake-id="ue597e2dd" id="ue597e2dd">一般来说，慢SQL的问题，是比较容易能够发现的。首先如果有很成熟的监控体系的话，会把慢SQL进行统计，然后以报警的形式推送出来。</span></p>
  <p data-lake-id="udc4fe1dd" id="udc4fe1dd"><span data-lake-id="u61f7cee5" id="u61f7cee5">​</span><br></p>
  <p data-lake-id="ud849cb4e" id="ud849cb4e"><span data-lake-id="uec87c537" id="uec87c537">如果用了一些数据库的中间件，他们也会有慢SQL的日志，如TDDL：</span></p>
  <p data-lake-id="u0f4b50ce" id="u0f4b50ce"><span data-lake-id="ue22bd398" id="ue22bd398">​</span><br></p>
  <pre lang="java"><code>
Cause: ERR-CODE: [TDDL-4202][ERR_SQL_QUERY_TIMEOUT] Slow query leads to a timeout exception, please contact DBA to check slow sql. SocketTimout:12000 ms, 
</code></pre>
  <p data-lake-id="uc5bcb740" id="uc5bcb740"><span data-lake-id="uefd10fe0" id="uefd10fe0">​</span><br></p>
  <p data-lake-id="u4c1762ce" id="u4c1762ce"><span data-lake-id="uea793361" id="uea793361">如果中间件也没用，那么数据库自己也是可以配置慢SQL日志的，配置方式如下：</span></p>
  <p data-lake-id="u316f90c8" id="u316f90c8"><span data-lake-id="ua26853eb" id="ua26853eb">​</span><br></p>
  <p data-lake-id="u54a2cb4e" id="u54a2cb4e"><span data-lake-id="uaf0d390a" id="uaf0d390a">1、找到MySQL的配置文件 my.cnf（或 my.ini，取决于操作系统），通常位于MySQL安装目录下的 etc 或 conf 文件夹。</span></p>
  <p data-lake-id="u4dcf7078" id="u4dcf7078"><span data-lake-id="u559f4e53" id="u559f4e53">2、在配置文件中启用慢查询日志：找到或添加以下配置项，并取消注释（如果有注释），确保以下行存在或添加到配置文件中：</span></p>
  <p data-lake-id="u67b68ea5" id="u67b68ea5"><span data-lake-id="u5a9675dd" id="u5a9675dd">​</span><br></p>
  <pre lang="java"><code>
slow_query_log = 1
slow_query_log_file = /path/to/slow-query.log
long_query_time = 1
</code></pre>
  <p data-lake-id="ubc7faec2" id="ubc7faec2"><span data-lake-id="u847453ee" id="u847453ee">​</span><br></p>
  <p data-lake-id="ue4ce431e" id="ue4ce431e"><span data-lake-id="u89299646" id="u89299646">3、重启MySQL服务：保存配置文件并重新启动MySQL服务，使配置生效。</span></p>
  <p data-lake-id="u21aa3173" id="u21aa3173"><span data-lake-id="uc7090a4d" id="uc7090a4d">​</span><br></p>
  <p data-lake-id="u24133726" id="u24133726"><span data-lake-id="u80b929ac" id="u80b929ac">配置生效后，如果有SQL的执行时长超过long_query_time 配置的时间阈值，那么就会打印慢SQL日志</span></p>
  <p data-lake-id="u14206b32" id="u14206b32"><span data-lake-id="u363eab65" id="u363eab65">​</span><br></p>
  <p data-lake-id="u00ba6c21" id="u00ba6c21"><span data-lake-id="ub513589c" id="ub513589c">4、查看慢查询日志：使用文本编辑器打开慢查询日志文件，路径为在配置文件中指定的路径。例如，在Linux上可以使用以下命令：</span></p>
  <p data-lake-id="udb3a279f" id="udb3a279f"><span data-lake-id="u7aaaff58" id="u7aaaff58">​</span><br></p>
  <pre lang="java"><code>
vim /path/to/slow-query.log
</code></pre>
  <p data-lake-id="u173596c3" id="u173596c3"><span data-lake-id="uaa8b2d16" id="uaa8b2d16">​</span><br></p>
  <p data-lake-id="u2013fb2e" id="u2013fb2e"><span data-lake-id="u377ad83f" id="u377ad83f">如果有慢SQL，内容如下：</span></p>
  <p data-lake-id="ucfd15da4" id="ucfd15da4"><span data-lake-id="uaa6157b5" id="uaa6157b5">​</span><br></p>
  <pre lang="java"><code>
# Time: 2023-06-04T12:00:00.123456Z
# User@Host: hollis[192.168.0.1]:3306
# Query_time: 2.345678  Lock_time: 0.012345 Rows_sent: 10  Rows_examined: 100
SET timestamp=1650000000;
SELECT * FROM orders WHERE status = 'pending' ORDER BY gmt_created DESC;
</code></pre>
  <p data-lake-id="u3972bbab" id="u3972bbab"><span data-lake-id="u2d021583" id="u2d021583">​</span><br></p>
  <h3 data-lake-id="pSp1X" id="pSp1X"><span data-lake-id="u615dbb45" id="u615dbb45">定位问题</span></h3>
  <p data-lake-id="u134d1c79" id="u134d1c79"><br></p>
  <p data-lake-id="uc2b2a384" id="uc2b2a384"><span data-lake-id="u5d815814" id="u5d815814">在如上的各种监控、报警以及日志中，我们就可以找到对应的慢SQL的具体SQL了，然后就可以进一步分析为什么这个SQL是慢SQL了，主要就是排查一下他慢在哪里。</span></p>
  <p data-lake-id="u953df84f" id="u953df84f"><span data-lake-id="u054c58ef" id="u054c58ef">​</span><br></p>
  <p data-lake-id="u7c2a6043" id="u7c2a6043"><span data-lake-id="ua5bebbec" id="ua5bebbec">一般来说，导致一个SQL慢的常见原因有以下几个：</span></p>
  <p data-lake-id="ufb0858b0" id="ufb0858b0"><span data-lake-id="ubeaf83fd" id="ubeaf83fd">​</span><br></p>
  <p data-lake-id="uddb77094" id="uddb77094"><span data-lake-id="u0958ea9d" id="u0958ea9d">1、没有索引</span></p>
  <p data-lake-id="u0b9f6c61" id="u0b9f6c61"><span data-lake-id="u7676f2d2" id="u7676f2d2">2、用错索引（没有遵守最左前缀、索引区分度不高）</span></p>
  <p data-lake-id="u0c6c5e00" id="u0c6c5e00"><span data-lake-id="u8b034432" id="u8b034432">3、查询字段太多</span></p>
  <p data-lake-id="u138278a9" id="u138278a9"><span data-lake-id="u82675791" id="u82675791">4、回表次数多</span></p>
  <p data-lake-id="ue2b88511" id="ue2b88511"><span data-lake-id="u0a015e30" id="u0a015e30">5、多表join</span></p>
  <p data-lake-id="ud296269a" id="ud296269a"><span data-lake-id="uafff0e38" id="uafff0e38">6、深度分页</span></p>
  <p data-lake-id="u436de57e" id="u436de57e"><span data-lake-id="uf16da2e9" id="uf16da2e9">7、...其他...</span></p>
  <p data-lake-id="u10dfc5c2" id="u10dfc5c2"><span data-lake-id="u67b84b2e" id="u67b84b2e">​</span><br></p>
  <p data-lake-id="uf9b7eb0a" id="uf9b7eb0a"><span data-lake-id="u4e705006" id="u4e705006">详见：</span></p>
  <p data-lake-id="uf7358969" id="uf7358969"><span data-lake-id="u75f517b9" id="u75f517b9">​</span><br></p>
  <p data-lake-id="uda891ffe" id="uda891ffe"><span data-lake-id="ub5981985" id="ub5981985">​</span><br></p>
  <p data-lake-id="udf2b0496" id="udf2b0496"><span data-lake-id="ue89c081e" id="ue89c081e">​</span><br></p>
  <p data-lake-id="u41e9ee0c" id="u41e9ee0c"><span data-lake-id="u6f366f4c" id="u6f366f4c">一般来说，大多数情况，是可以通过执行计划分析出一条SQL的慢的原因的，大部分来说，主要是索引的问题和join的问题了。</span></p>
  <p data-lake-id="ua78cb519" id="ua78cb519"><span data-lake-id="uf0bce63f" id="uf0bce63f">​</span><br></p>
  <p data-lake-id="uc892fd1b" id="uc892fd1b"><span data-lake-id="ub4893da9" id="ub4893da9">关于执行计划的分析，索引失效等可以参考下面几篇，介绍的很详细了：</span></p>
  <p data-lake-id="u8965e014" id="u8965e014"><span data-lake-id="u778c5902" id="u778c5902">​</span><br></p>
  <p data-lake-id="uf9976b49" id="uf9976b49"><br></p>
  <p data-lake-id="u8daad891" id="u8daad891"><span data-lake-id="u73dcbb2e" id="u73dcbb2e">​</span><br></p>
  <h3 data-lake-id="qvlzb" id="qvlzb"><span data-lake-id="ud6f4d226" id="ud6f4d226">解决问题</span></h3>
  <p data-lake-id="u6e31d408" id="u6e31d408"><br></p>
  <p data-lake-id="u65ee9dad" id="u65ee9dad"><span data-lake-id="uee88cba2" id="uee88cba2">在定位到问题之后，就是解决了</span></p>
  <p data-lake-id="u21ef5d03" id="u21ef5d03"><span data-lake-id="u5e9bed42" id="u5e9bed42">​</span><br></p>
  <p data-lake-id="u39de1e51" id="u39de1e51"><span data-lake-id="ufded4f8b" id="ufded4f8b">其实最难的不是解决问题，而是定位问题，因为一旦一个问题被定位到了，解决起来都比较容易。缺索引就加索引，join太多就拆分就好了。这里就不展开说了。</span></p>
  <p data-lake-id="uf26a8985" id="uf26a8985"><span data-lake-id="u3fa97566" id="u3fa97566">​</span><br></p>
  <p data-lake-id="u1f42671b" id="u1f42671b"><span data-lake-id="u47ec4fce" id="u47ec4fce">下面是一个慢SQL排查的实际案例，和本文的思路是一样的：</span></p>
  <p data-lake-id="uf0fc5e29" id="uf0fc5e29"><span data-lake-id="u1f545958" id="u1f545958">​</span><br></p>
  <p data-lake-id="ubd23d26a" id="ubd23d26a"><span data-lake-id="ufb6d3872" id="ufb6d3872">​</span><br></p>
  <p data-lake-id="u8f5a7425" id="u8f5a7425"><span data-lake-id="uf9c16f88" id="uf9c16f88">​</span><br></p>
 </body>
</html>